package com.resource;

import com.resource.error.AuthenticationAccessDeniedHandler;
import com.resource.error.CustomAuthenticationEntryPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.client.RestTemplate;

/**
 * 资源服务器
 * @author HeWei123
 */
@Configuration
@Slf4j
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    @Autowired
    private AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;

    @Autowired
    private DefaultTokenServices defaultTokenServices;

    @Value("${spring.application.name}")
    private String applicationName;


    /**
     * 该方法用于定义资源服务器向远程认证服务器发起请求，进行token校验等事宜
     *
     * @param resources
     * @throws Exception
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
                .accessDeniedHandler(authenticationAccessDeniedHandler)
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                .resourceId(applicationName)
                .tokenStore(tokenStore)
                .tokenServices(defaultTokenServices);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    /**
     * 场景:一个服务中可能有很多资源(API接口)
     *     某一些API接口，需要先认证，才能访问
     *     某一些API接口，压根就不需要认证，本来就是对外开放的接口
     *     我们就需要对不同特点的接口区分对待(在当前configure方法中完成)，设置是否需要经过认证
     *
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http // 设置session的创建策略(根据需要创建即可)
                .csrf()
                .disable()
                .authorizeRequests()
                // 不认证/common为前缀
                .antMatchers("/common/**").permitAll()
                // 验证/system 为前缀
                .antMatchers("/system/**").authenticated()
                .anyRequest().authenticated();




    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

}
